﻿#include "DAAbstractNode.h"
#include "DAAbstractNodeGraphicsItem.h"
#include "DANodeMetaData.h"
#include "DAWorkFlow.h"
#include "DAAbstractNodeFactory.h"
// QVariant cast use
#include <math.h>
#include <QBitArray>
#include <QBitmap>
#include <QBrush>
#include <QByteArray>
#include <QCursor>
#include <QDataStream>
#include <QDate>
#include <QEasingCurve>
#include <QFont>
#include <QIcon>
#include <QImage>
#include <QKeySequence>
#include <QLocale>
#include <QMatrix4x4>
#include <QMatrix>
#include <QPalette>
#include <QPen>
#include <QPolygon>
#include <QQuaternion>
#include <QRegularExpression>
#include <QSizePolicy>
#include <QStringList>
#include <QTextFormat>
#include <QTextLength>
#include <QTransform>
#include <QUrl>
#include <QUuid>
#include <QVector2D>
#include <QVector3D>
#include <QVector4D>
#include <QPointer>
// Qxml
#include <QDomComment>
#include <QDomElement>
#define SANODE_DEBUG_PRINT

namespace DA
{
class DAAbstractNodePrivate
{
    DA_IMPL_PUBLIC(DAAbstractNode)
public:
    class LinkData
    {
    public:
        using NodeSharedPtr = DAAbstractNode::SharedPointer;
        using NodeWeakPtr   = std::weak_ptr< DAAbstractNode >;
        LinkData();
        LinkData(const NodeSharedPtr& inNode, const QString& inKey);
        LinkData(const NodeSharedPtr& outNode, const QString& outKey, const NodeSharedPtr& inNode, const QString& inKey);
        bool operator==(const LinkData& d);
        NodeWeakPtr inputNode;
        QString inputKey;
        NodeWeakPtr outputNode;
        QString outputKey;
    };
    QList< LinkData > getOutputLinkData(const QString& k);
    QList< LinkData > getInputLinkData(const QString& k);

public:
    DAAbstractNodePrivate(DAAbstractNode* p);
    DANodeMetaData _meta;
    QList< LinkData > _linksInfo;            ///< 记录所有连接信息
    QHash< QString, QVariant > _inputData;   ///< 节点输入数据
    QHash< QString, QVariant > _outputData;  ///< 节点输出数据
    QHash< QString, QVariant > _propertys;   ///< 属性数据
    DAAbstractNode::IdType _id;
    QPointer< DAWorkFlow > _workflow;            ///< 持有的workflow
    DAAbstractNodeGraphicsItem* _item;           ///< node 对应的item
    QPointer< DAAbstractNodeFactory > _factory;  ///< 保存节点的工厂，工厂的设置在DAWorkFlow::createNode中
};
}

using namespace DA;
//================================================
// DAAbstractNodePrivate::LinkData
//================================================

DAAbstractNodePrivate::LinkData::LinkData()
{
}

DAAbstractNodePrivate::LinkData::LinkData(const NodeSharedPtr& inNode, const QString& inKey)
    : inputNode(inNode), inputKey(inKey)
{
}

DAAbstractNodePrivate::LinkData::LinkData(const DAAbstractNodePrivate::LinkData::NodeSharedPtr& outNode,
                                          const QString& outKey,
                                          const DAAbstractNodePrivate::LinkData::NodeSharedPtr& inNode,
                                          const QString& inKey)
    : outputNode(outNode), outputKey(outKey), inputNode(inNode), inputKey(inKey)
{
}

bool DAAbstractNodePrivate::LinkData::operator==(const DAAbstractNodePrivate::LinkData& d)
{
    return (inputNode.lock() == d.inputNode.lock()) && (inputKey == d.inputKey)
           && (outputNode.lock() == d.outputNode.lock()) && (outputKey == d.outputKey);
}

/**
 * @brief 获取out节点名字下的所有LinkData
 * @param k
 * @return
 */
QList< DAAbstractNodePrivate::LinkData > DAAbstractNodePrivate::getOutputLinkData(const QString& k)
{
    QList< DAAbstractNodePrivate::LinkData > res;
    for (const LinkData& d : qAsConst(_linksInfo)) {
        if (d.outputNode.lock().get() == q_ptr && d.outputKey == k) {
            res.append(d);
        }
    }
    return res;
}

/**
 * @brief DAAbstractNodePrivate::getInputLinkData
 * @param k
 * @return
 */
QList< DAAbstractNodePrivate::LinkData > DAAbstractNodePrivate::getInputLinkData(const QString& k)
{
    QList< DAAbstractNodePrivate::LinkData > res;
    for (const LinkData& d : qAsConst(_linksInfo)) {
        if (d.inputNode.lock().get() == q_ptr && d.inputKey == k) {
            res.append(d);
        }
    }
    return res;
}

DAAbstractNodePrivate::DAAbstractNodePrivate(DAAbstractNode* p) : q_ptr(p), _item(nullptr)
{
    _id = p->generateID();
}

//================================================
// DAAbstractNode::LinkInfo
//================================================

DAAbstractNode::LinkInfo::LinkInfo()
{
}

//================================================
// DAAbstractNode
//================================================

DAAbstractNode::DAAbstractNode() : d_ptr(new DAAbstractNodePrivate(this))
{
}

/**
 * @brief 节点的销毁，节点销毁过程会通知相关联的节点把自己信息解除
 */
DAAbstractNode::~DAAbstractNode()
{
    detachAll();
}

/**
 * @brief 获取节点的名字
 * @return
 */
QString DAAbstractNode::getNodeName() const
{
    return (d_ptr->_meta.getNodeName());
}

/**
 * @brief 设置节点名
 * @param name
 * @note 此函数会导致关联的DAWorkFlow发射nodeNameChanged信号@sa DAWorkFlow::nodeNameChanged
 * @note 此函数为虚函数，在一些场合需要对名字进行校验的特殊节点可继承此函数来进行校验，但记得调用DAAbstractNode::setNodeName使之生效
 */
void DAAbstractNode::setNodeName(const QString& name)
{
    QString oldname = d_ptr->_meta.getNodeName();
    d_ptr->_meta.setNodeName(name);
    if (d_ptr->_workflow) {
        d_ptr->_workflow->emitNodeNameChanged(shared_from_this(), oldname, name);
    }
}

/**
 * @brief FCAbstractNode::getNodePrototype
 * @return
 */
QString DAAbstractNode::getNodePrototype() const
{
    return (d_ptr->_meta.getNodePrototype());
}

/**
 * @brief 获取分组
 * @return
 */
QString DAAbstractNode::getNodeGroup() const
{
    return d_ptr->_meta.getGroup();
}

/**
 * @brief FCAbstractNodeGraphicsItem::getIcon
 * @return
 */
QIcon DAAbstractNode::getIcon() const
{
    return (d_ptr->_meta.getIcon());
}

/**
 * @brief 设置图标
 * @param icon
 */
void DAAbstractNode::setIcon(const QIcon& icon)
{
    d_ptr->_meta.setIcon(icon);
}

/**
 * @brief 获取节点元数据
 * @return
 */
const DANodeMetaData& DAAbstractNode::metaData() const
{
    return (d_ptr->_meta);
}

/**
 * @brief 获取节点元数据
 * @return
 */
DANodeMetaData& DAAbstractNode::metaData()
{
    return (d_ptr->_meta);
}

/**
 * @brief 说明
 * @return
 */
QString DAAbstractNode::getNodeTooltip() const
{
    return (d_ptr->_meta.getNodeTooltip());
}

/**
 * @brief 说明
 * @param tp
 */
void DAAbstractNode::setNodeTooltip(const QString& tp)
{
    d_ptr->_meta.setNodeTooltip(tp);
}

/**
 * @brief 设置元数据
 * @param metadata
 */
void DAAbstractNode::setMetaData(const DANodeMetaData& metadata)
{
    d_ptr->_meta = metadata;
}

/**
 * @brief 返回自身的引用
 * @return
 */
DAAbstractNode::SharedPointer DAAbstractNode::pointer()
{
    return (shared_from_this());
}

/**
 * @brief 获取id
 * @see setID generateID
 * @return
 */
DAAbstractNode::IdType DAAbstractNode::getID() const
{
    return d_ptr->_id;
}

/**
 * @brief 设置id
 * @see getID generateID
 * @param d
 */
void DAAbstractNode::setID(const IdType& d)
{
    d_ptr->_id = d;
}

/**
 * @brief 设置属性
 * @note 如果节点有一些额外属性，通过此函数保存才能存入文件系统中
 * @param k 属性键值
 * @param v 属性值
 */
void DAAbstractNode::setProperty(const QString& k, const QVariant& v)
{
    d_ptr->_propertys[ k ] = v;
}

/**
 * @brief 读取属性
 * @note 如果节点有一些额外属性，通过此函数保存才能存入文件系统中
 * @param k
 * @param defaultVal
 * @return
 */
QVariant DAAbstractNode::getProperty(const QString& k, const QVariant& defaultVal) const
{
    return d_ptr->_propertys.value(k, defaultVal);
}

/**
 * @brief 移除属性
 * @param k
 */
bool DAAbstractNode::removeProperty(const QString& k)
{
    return d_ptr->_propertys.remove(k);
}

/**
 * @brief 获取所以得属性关键字
 * @return
 */
QList< QString > DAAbstractNode::getPropertyKeys() const
{
    return d_ptr->_propertys.keys();
}

/**
 * @brief 把信息保存到xml上
 *
 * DAAbstractNode的此函数不会实现任何功能，继承的node要保存一些参数可以通过继承此函数实现
 * @param doc
 * @param parentElement
 */
void DAAbstractNode::saveExternInfoToXml(QDomDocument* doc, QDomElement* nodeElement) const
{
    Q_UNUSED(doc);
    Q_UNUSED(nodeElement);
}
/**
 * @brief 从xml加载扩展信息
 *
 * DAAbstractNode的此函数不会实现任何功能，继承的node要加载一些参数可以通过继承此函数实现
 * @param parentElement
 */
void DAAbstractNode::loadExternInfoFromXml(const QDomElement* nodeElement)
{
    Q_UNUSED(nodeElement);
}

/**
 * @brief 获取说有的输入参数
 * @return
 */
QList< QString > DAAbstractNode::getInputKeys() const
{
    return d_ptr->_inputData.keys();
}

/**
 * @brief 获取所有的输出参数
 * @return
 */
QList< QString > DAAbstractNode::getOutputKeys() const
{
    return d_ptr->_outputData.keys();
}

/**
 * @brief 添加一个输入参数
 * @param k
 */
void DAAbstractNode::addInputKey(const QString& k)
{
    d_ptr->_inputData[ k ] = QVariant();
}
/**
 * @brief 添加一个输出参数
 * @param k
 */
void DAAbstractNode::addOutputKey(const QString& k)
{
    d_ptr->_outputData[ k ] = QVariant();
}

/**
 * @brief 建立连接,从out到另外一个item的in
 * @param outpt 输出点
 * @param toItem 输入的item
 * @param topt 输入点
 * @return 成功返回true
 */
bool DAAbstractNode::linkTo(const QString& outKey, DAAbstractNode::SharedPointer inNode, const QString& inKey)
{
    if (!getOutputKeys().contains(outKey)) {
        qCritical() << "invalid link [" << getNodeName() << "] can not find out key " << outKey;
        return (false);
    }
    if (!(inNode->getInputKeys().contains(inKey))) {
        qCritical() << "invalid link [" << inNode->getNodeName() << "] can not find in Key " << inKey;
        return (false);
    }
    DAAbstractNodePrivate::LinkData ld(pointer(), outKey, inNode, inKey);
    d_ptr->_linksInfo.append(ld);             //当前记录连接信息
    inNode->d_func()->_linksInfo.append(ld);  //被连接的节点也记录下连接信息
    if (DAAbstractNodeFactory* f = factory()) {
        f->nodeLinkSucceed(pointer(), outKey, inNode, inKey);
    }
    return (true);
}

/**
 * @brief detachToLink会对_toNode进行删除操作，因此不允许在_toNode迭代环境中调用此函数
 * @param outpt
 * @return
 */
bool DAAbstractNode::detachLink(const QString& key)
{
    QList< DAAbstractNodePrivate::LinkData > outs = d_ptr->getOutputLinkData(key);
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(outs)) {
        d_ptr->_linksInfo.removeAll(d);
        SharedPointer inputNode = d.inputNode.lock();
        if (inputNode && inputNode.get() != this) {
            //说明这个是从本身连接到其他，则其他节点也需要删除这个链接
            inputNode->d_func()->_linksInfo.removeAll(d);
            //通知工厂的回调函数
            if (DAAbstractNodeFactory* f = factory()) {
                f->nodeLinkDetached(d.outputNode.lock(), d.outputKey, inputNode, d.inputKey);
            }
        }
    }
    QList< DAAbstractNodePrivate::LinkData > ins = d_ptr->getInputLinkData(key);
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(ins)) {
        d_ptr->_linksInfo.removeAll(d);
        SharedPointer outputNode = d.outputNode.lock();
        if (outputNode && outputNode.get() != this) {
            //说明这个是从本身连接到其他，则其他节点也需要删除这个链接
            outputNode->d_func()->_linksInfo.removeAll(d);
            //通知工厂的回调函数
            if (DAAbstractNodeFactory* f = factory()) {
                f->nodeLinkDetached(outputNode, d.outputKey, pointer(), d.inputKey);
            }
        }
    }
    return (ins.size() + outs.size()) > 0;
}

/**
 * @brief 移除所有依赖，一般是节点被删除时会调用此函数
 */
void DAAbstractNode::detachAll()
{
#ifdef SANODE_DEBUG_PRINT
    qDebug() << "---------------------------";
    qDebug() << "-start detachAll"
             << "\n- node name:" << getNodeName() << ",prototype:" << metaData().getNodePrototype() << "\n- link infos:";
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        SharedPointer from = d.outputNode.lock();
        SharedPointer to   = d.inputNode.lock();
        if (from && to) {
            qDebug().noquote() << from->getNodeName() << "[" << d.outputKey << "] -> " << to->getNodeName() << "["
                               << d.inputKey << "]";
        } else if (from && to == nullptr) {
            qDebug().noquote() << from->getNodeName() << "[" << d.outputKey << "] -> "
                               << "null";
        } else if (from == nullptr && to) {
            qDebug().noquote() << "null -> " << to->getNodeName() << "[" << d.inputKey << "]";
        } else {
            qDebug().noquote() << "null -> null";
        }
    }
#endif
    //! 不能直接迭代_toNode过程调用detachToLink，会导致迭代器失效
    //清空关系
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        SharedPointer toItem = d.inputNode.lock();
        if (toItem && toItem.get() != this) {
            //说明这个是从本身连接到其他，则其他节点也需要删除这个链接
            toItem->d_func()->_linksInfo.removeAll(d);
            //通知工厂的回调函数
            if (DAAbstractNodeFactory* f = factory()) {
                f->nodeLinkDetached(d.outputNode.lock(), d.outputKey, d.inputNode.lock(), d.inputKey);
            }
        }
    }
    d_ptr->_linksInfo.clear();
}

/**
 * @brief 获取所有连接了输入keys的节点
 * @return 返回连接了node的input keys的节点
 */
QList< DAAbstractNode::SharedPointer > DAAbstractNode::getInputNodes() const
{
    QList< DAAbstractNode::SharedPointer > res;
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        SharedPointer toNode = d.inputNode.lock();
        if (toNode.get() == this) {
            //说明这个是其他节点连接到自身的item
            SharedPointer fromNode = d.outputNode.lock();
            if (fromNode) {
                res.append(fromNode);
            }
        }
    }
    return res;
}

/**
 * @brief 获取此节点输出到其他的节点
 * @return
 */
QList< DAAbstractNode::SharedPointer > DAAbstractNode::getOutputNodes() const
{
    QList< DAAbstractNode::SharedPointer > res;
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        SharedPointer fromNode = d.outputNode.lock();
        if (fromNode.get() == this) {
            //说明这个是此节点连接到其他的node
            SharedPointer toNode = d.inputNode.lock();
            if (toNode) {
                res.append(toNode);
            }
        }
    }
    return res;
}

/**
 * @brief 获取输入节点的数量
 * @return
 */
int DAAbstractNode::getInputNodesCount() const
{
    int res = 0;
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        SharedPointer toNode = d.inputNode.lock();
        if (toNode.get() == this) {
            //说明这个是其他节点连接到自身的item
            ++res;
        }
    }
    return res;
}

/**
 * @brief 获取输出节点的数量
 * @return
 */
int DAAbstractNode::getOutputNodesCount() const
{
    int res = 0;
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        SharedPointer fromNode = d.outputNode.lock();
        if (fromNode.get() == this) {
            //说明这个是此节点连接到其他的node
            ++res;
        }
    }
    return res;
}

/**
 * @brief 获取输入的节点，如果没有，返回nullptr
 * @param inputkey
 * @return
 */
DAAbstractNode::SharedPointer DAAbstractNode::getInputNode(const QString inputkey) const
{
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        if (inputkey == d.inputKey) {
            //连接的to key和input一致，说明这个链接对于此节点是接入
            return d.outputNode.lock();
        }
    }
    return nullptr;
}

/**
 * @brief 获取输出的节点，如果没有，返回nullptr
 * @param outputkey
 * @return
 */
DAAbstractNode::SharedPointer DAAbstractNode::getOutputNode(const QString outputkey) const
{
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        if (outputkey == d.outputKey) {
            //连接的from key和output一致，说明这个链接对于此节点是接出
            return d.inputNode.lock();
        }
    }
    return nullptr;
}

/**
 * @brief 输入参数
 * @param inputName
 * @param dp 数据会发生拷贝操作，不会影响原来数据包
 */
void DAAbstractNode::setInputData(const QString& key, const QVariant& dp)
{
    d_ptr->_inputData[ key ] = dp;
}

/**
 * @brief FCAbstractNode::inputData
 * @param key
 * @return
 */
QVariant DAAbstractNode::getInputData(const QString& key)
{
    return (d_ptr->_inputData.value(key));
}

QVariant DAAbstractNode::getOutputData(const QString& key)
{
    return (d_ptr->_outputData.value(key));
}

/**
 * @brief 获取所有输入（入度）的信息
 * @return
 */
QList< DAAbstractNode::LinkInfo > DAAbstractNode::getAllInputLinkInfo() const
{
    QHash< QString, DAAbstractNode::LinkInfo > res;
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        SharedPointer n = d.inputNode.lock();
        if (n.get() == this) {
            //说明输出节点是自己
            SharedPointer outputNode = d.outputNode.lock();
            if (!outputNode) {
                continue;
            }
            auto ite = res.find(d.inputKey);
            if (ite == res.end()) {
                ite             = res.insert(d.inputKey, DAAbstractNode::LinkInfo());
                ite.value().key = d.inputKey;
            }
            ite.value().nodes.append(qMakePair(d.outputKey, outputNode));
        }
    }
    return res.values();
}

/**
 * @brief 获取输出（出度）的链接信息
 * @return
 */
QList< DAAbstractNode::LinkInfo > DAAbstractNode::getAllOutputLinkInfo() const
{
    QHash< QString, DAAbstractNode::LinkInfo > res;
    for (const DAAbstractNodePrivate::LinkData& d : qAsConst(d_ptr->_linksInfo)) {
        SharedPointer n = d.outputNode.lock();
        if (n.get() == this) {
            //说明输出节点是自己
            SharedPointer inputnode = d.inputNode.lock();
            if (!inputnode) {
                continue;
            }
            auto ite = res.find(d.outputKey);
            if (ite == res.end()) {
                ite             = res.insert(d.outputKey, DAAbstractNode::LinkInfo());
                ite.value().key = d.outputKey;
            }
            ite.value().nodes.append(qMakePair(d.inputKey, inputnode));
        }
    }
    return res.values();
}
/**
 * @brief 生成一个唯一id
 * @return
 */
DAAbstractNode::IdType DAAbstractNode::generateID() const
{
    union {
        IdType id;
        uint32_t raw[ 2 ];
    } mem;
    QDateTime dt = QDateTime::currentDateTime();
    mem.raw[ 0 ] = uint32_t(dt.toTime_t());
    mem.raw[ 1 ] = uintptr_t(this);
    return mem.id;
}

/**
 * @brief 获取工作流
 * @return
 */
DAWorkFlow* DAAbstractNode::workflow() const
{
    return d_ptr->_workflow;
}

/**
 * @brief 获取工厂
 * @return
 */
DAAbstractNodeFactory* DAAbstractNode::factory() const
{
    return d_ptr->_factory.data();
}

/**
 * @brief 获取graphicsItem
 * @return
 */
DAAbstractNodeGraphicsItem* DAAbstractNode::graphicsItem()
{
    return d_ptr->_item;
}
/**
 * @brief 获取graphicsItem
 * @return
 */
const DAAbstractNodeGraphicsItem* DAAbstractNode::graphicsItem() const
{
    return d_ptr->_item;
}

/**
 * @brief 记录item，此函数在DAAbstractNodeGraphicsItem构造函数中调用
 * @param it
 * @note 在createGraphicsItem时，构造DAAbstractNodeGraphicsItem就会在
 * DAAbstractNodeGraphicsItem的构造函数中调用此函数记录DAAbstractNodeGraphicsItem
 */
void DAAbstractNode::registItem(DAAbstractNodeGraphicsItem* it)
{
    if (d_ptr->_item) {
        //这种情况说明用户误操作，一般是调用了两次createGraphicsItem
        qCritical() << "node regist item more than one";
    }
    d_ptr->_item = it;
}

/**
 * @brief 解除对item的记录
 * 在某些环境下，删除item就会调用此函数解除item的记录
 */
void DAAbstractNode::unregistItem()
{
    d_ptr->_item = nullptr;
}

/**
 * @brief 设置输出的参数
 * @param key
 * @param dp
 */
void DAAbstractNode::setOutputData(const QString& key, const QVariant& dp)
{
    d_ptr->_outputData[ key ] = dp;
}
/**
 * @brief 移除输入,如果有数据，数据也会移除
 * @param key
 */
void DAAbstractNode::removeInputKey(const QString& key)
{
    d_ptr->_inputData.remove(key);
}
/**
 * @brief 移除输出,如果有数据，数据也会移除
 * @param key
 */
void DAAbstractNode::removeOutputKey(const QString& key)
{
    d_ptr->_outputData.remove(key);
}

/**
 * @brief 记录DAWorkFlow
 * @param wf
 */
void DAAbstractNode::registWorkflow(DAWorkFlow* wf)
{
    d_ptr->_workflow = wf;
}

/**
 * @brief 记录工厂
 * @param fc
 */
void DAAbstractNode::registFactory(DAAbstractNodeFactory* fc)
{
    d_ptr->_factory = fc;
}

/**
 * @brief 把当前注册的工作流取消
 */
void DAAbstractNode::unregistWorkflow()
{
    d_ptr->_workflow = nullptr;
}

/**
 * @brief 把当前注册的工厂取消
 */
void DAAbstractNode::unregistFactory()
{
    d_ptr->_factory = nullptr;
}

QString DA::variantToString(const QVariant& var)
{
    switch (var.type()) {
    case QVariant::Invalid:
        return (QString());

    case QVariant::BitArray:
        return (converVariantToBase64String< QBitArray >(var));

    case QVariant::Bitmap:
        return (converVariantToBase64String< QBitmap >(var));

    case QVariant::Bool:
        return (var.toBool() ? "1" : "0");

    case QVariant::Brush:
        return (converVariantToBase64String< QBrush >(var));

    case QVariant::ByteArray:
        return (converVariantToBase64String< QByteArray >(var));

    case QVariant::Char:
        return (var.toChar());

    case QVariant::Color: {
        QColor clr = var.value< QColor >();
        return (clr.name(QColor::HexArgb));
    }

    case QVariant::Cursor:
        return (converVariantToBase64String< QCursor >(var));

    case QVariant::Date: {
        QDate d = var.toDate();
        return (d.toString(Qt::ISODate));
    }

    case QVariant::DateTime: {
        QDateTime d = var.toDateTime();
        return (d.toString(Qt::ISODate));
    }

    case QVariant::Double: {
        double d = var.toDouble();
        return (doubleToString(d));  //针对double，用非科学计数法会对小数丢失精度，因此采样g最合理，但小数点较多时需要适当处理
    }

    case QVariant::EasingCurve: {
        return (converVariantToBase64String< QEasingCurve >(var));
    }

    case QVariant::Uuid: {
        return (var.toUuid().toString());
    }

    case QVariant::Font: {
        return (converVariantToBase64String< QFont >(var));
    }

    case QVariant::Hash: {
        return (converVariantToBase64String< QVariantHash >(var));
    }

    case QVariant::Icon: {
        return (converVariantToBase64String< QIcon >(var));
    }

    case QVariant::Image: {
        return (converVariantToBase64String< QImage >(var));
    }

    case QVariant::Int: {
        return (QString::number(var.toInt()));
    }

    case QVariant::KeySequence: {
        QKeySequence d = var.value< QKeySequence >();
        return (d.toString(QKeySequence::NativeText));
    }

    case QVariant::Line: {
        QLine d = var.toLine();
        return (QString("%1;%2;%3;%4").arg(d.x1()).arg(d.y1()).arg(d.x2()).arg(d.y2()));
    }

    case QVariant::LineF: {
        QLineF d = var.toLineF();
        return (QString("%1;%2;%3;%4").arg(doubleToString(d.x1()), doubleToString(d.y1()), doubleToString(d.x2()), doubleToString(d.y2())));
    }

    case QVariant::List: {
        return (converVariantToBase64String< QVariantList >(var));
    }

    case QVariant::Locale: {
        return (var.toLocale().name());
    }

    case QVariant::LongLong: {
        return (QString::number(var.toLongLong()));
    }

    case QVariant::Map: {
        return (converVariantToBase64String< QVariantMap >(var));
    }

    case QVariant::Matrix: {
        QMatrix d = var.value< QMatrix >();
        return (QString("%1;%2;%3;%4;%5;%6").arg(d.m11()).arg(d.m12()).arg(d.m21()).arg(d.m22()).arg(d.dx()).arg(d.dy()));
    }

    case QVariant::Transform: {
        QTransform d = var.value< QTransform >();
        return (QString("%1;%2;%3;%4;%5;%6;%7;%8;%9")
                        .arg(d.m11())
                        .arg(d.m12())
                        .arg(d.m13())
                        .arg(d.m21())
                        .arg(d.m22())
                        .arg(d.m23())
                        .arg(d.m31())
                        .arg(d.m32())
                        .arg(d.m33()));
    }

    case QVariant::Matrix4x4: {
        QMatrix4x4 d = var.value< QMatrix4x4 >();
        return (QString("%1;%2;%3;%4;%5;%6;%7;%8;%9;%10;%11;%12;%13;%14;%15;%16")
                        .arg(d(0, 0))
                        .arg(d(0, 1))
                        .arg(d(0, 2))
                        .arg(d(0, 3))
                        .arg(d(1, 0))
                        .arg(d(1, 1))
                        .arg(d(1, 2))
                        .arg(d(1, 3))
                        .arg(d(2, 0))
                        .arg(d(2, 1))
                        .arg(d(2, 2))
                        .arg(d(2, 3))
                        .arg(d(3, 0))
                        .arg(d(3, 1))
                        .arg(d(3, 2))
                        .arg(d(3, 3)));
    }

    case QVariant::Palette: {
        return (converVariantToBase64String< QPalette >(var));
    }

    case QVariant::Pen: {
        return (converVariantToBase64String< QPen >(var));
    }

    case QVariant::Pixmap: {
        return (converVariantToBase64String< QPixmap >(var));
    }

    case QVariant::Point: {
        QPoint d = var.toPoint();
        return (QString("%1;%2").arg(d.x()).arg(d.y()));
    }

    case QVariant::PointF: {
        QPointF d = var.toPointF();
        return (QString("%1;%2").arg(doubleToString(d.x()), doubleToString(d.y())));
    }

    case QVariant::Polygon: {
        QPolygon d = var.value< QPolygon >();
        QString str;
        if (!d.isEmpty()) {
            str += QString("%1;%2").arg(d[ 0 ].x()).arg(d[ 0 ].y());
        }
        for (int i = 1; i < d.size(); ++i) {
            str += QString("|%1;%2").arg(d[ i ].x()).arg(d[ i ].y());
        }
        return (str);
    }

    case QVariant::PolygonF: {
        QPolygonF d = var.value< QPolygonF >();
        QString str;
        if (!d.isEmpty()) {
            ////用g,而不用f，f会导致小数位过多，并不适合协议传输，但针对double类型，默认是用f
            str += QString("%1;%2").arg(doubleToString(d[ 0 ].x()), doubleToString(d[ 0 ].y()));
        }
        //用非科学计数法转换，避免精度的丢失
        for (int i = 1; i < d.size(); ++i) {
            str += QString("|%1;%2").arg(doubleToString(d[ i ].x()), doubleToString(d[ i ].y()));
        }
        return (str);
    }

    case QVariant::Quaternion: {
        return (converVariantToBase64String< QQuaternion >(var));
    }

    case QVariant::Rect: {
        QRect d = var.toRect();
        return (QString("%1;%2;%3;%4").arg(d.x()).arg(d.y()).arg(d.width()).arg(d.height()));
    }

    case QVariant::RectF: {
        QRectF d = var.toRectF();
        return (QString("%1;%2;%3;%4").arg(doubleToString(d.x()), doubleToString(d.y()), doubleToString(d.width()), doubleToString(d.height())));
    }

    case QVariant::RegExp: {
        return (converVariantToBase64String< QRegExp >(var));
    }

    case QVariant::RegularExpression: {
        return (converVariantToBase64String< QRegularExpression >(var));
    }

    case QVariant::Region: {
        return (converVariantToBase64String< QRegion >(var));
    }

    case QVariant::Size: {
        QSize d = var.toSize();
        return (QString("%1;%2").arg(d.width()).arg(d.height()));
    }

    case QVariant::SizeF: {
        QSizeF d = var.toSizeF();
        return (QString("%1;%2").arg(doubleToString(d.width()), doubleToString(d.height())));
    }

    case QVariant::SizePolicy: {
        return (converVariantToBase64String< QSizePolicy >(var));
    }

    case QVariant::String: {
        return (var.toString());
    }

    case QVariant::StringList: {
        return (converVariantToBase64String< QStringList >(var));
    }

    case QVariant::TextFormat: {
        return (converVariantToBase64String< QTextFormat >(var));
    }

    case QVariant::TextLength: {
        return (converVariantToBase64String< QTextLength >(var));
    }

    case QVariant::Time: {
        return (var.toTime().toString(Qt::ISODate));
    }

    case QVariant::UInt: {
        return (QString::number(var.toUInt()));
    }

    case QVariant::ULongLong: {
        return (QString::number(var.toULongLong()));
    }

    case QVariant::Url: {
        return (var.toUrl().toString());
    }

    case QVariant::Vector2D: {
        return (converVariantToBase64String< QVector2D >(var));
    }

    case QVariant::Vector3D: {
        return (converVariantToBase64String< QVector3D >(var));
    }

    case QVariant::Vector4D: {
        return (converVariantToBase64String< QVector4D >(var));
    }

    default:
        return (QString());
    }
    return (QString());
}

QVariant DA::stringToVariant(const QString& var, const QString& typeName)
{
    QVariant::Type type = QVariant::nameToType(typeName.toLocal8Bit().data());

    switch (type) {
    case QVariant::Invalid:
        return (QVariant());

    case QVariant::BitArray:
        return (converBase64StringToVariant< QBitArray >(var));

    case QVariant::Bitmap:
        return (converBase64StringToVariant< QBitmap >(var));

    case QVariant::Bool: {
        bool d = var.toInt();
        return (d);
    }

    case QVariant::Brush:
        return (converBase64StringToVariant< QBrush >(var));

    case QVariant::ByteArray:
        return (converBase64StringToVariant< QByteArray >(var));

    case QVariant::Char: {
        if (var.size() <= 0) {
            return (QVariant());
        }
        return (QChar(var[ 0 ]));
    }

    case QVariant::Color: {
        QColor clr;
        clr.setNamedColor(var);
        return (clr);
    }

    case QVariant::Cursor:
        return (converBase64StringToVariant< QCursor >(var));

    case QVariant::Date: {
        QDate d;
        d.fromString(var, Qt::ISODate);
        return (d);
    }

    case QVariant::DateTime: {
        QDateTime d;
        d.fromString(var, Qt::ISODate);
        return (d);
    }

    case QVariant::Double: {
        double d = var.toDouble();
        return (d);
    }

    case QVariant::EasingCurve: {
        return (converBase64StringToVariant< QEasingCurve >(var));
    }

    case QVariant::Uuid: {
        QUuid d(var);
        return (d);
    }

    case QVariant::Font: {
        return (converBase64StringToVariant< QFont >(var));
    }

    case QVariant::Hash: {
        return (converBase64StringToVariant< QVariantHash >(var));
    }

    case QVariant::Icon: {
        return (converBase64StringToVariant< QIcon >(var));
    }

    case QVariant::Image: {
        return (converBase64StringToVariant< QImage >(var));
    }

    case QVariant::Int: {
        return (QString::number(var.toInt()));
    }

    case QVariant::KeySequence: {
        QKeySequence d(var, QKeySequence::NativeText);
        return (d);
    }

    case QVariant::Line: {
        QStringList list = var.split(';');
        if (list.size() != 4) {
            return (QVariant());
        }
        QLine d(list[ 0 ].toInt(), list[ 1 ].toInt(), list[ 2 ].toInt(), list[ 3 ].toInt());
        return (d);
    }

    case QVariant::LineF: {
        QStringList list = var.split(';');
        if (list.size() != 4) {
            return (QVariant());
        }
        QLineF d(list[ 0 ].toDouble(), list[ 1 ].toDouble(), list[ 2 ].toDouble(), list[ 3 ].toDouble());
        return (d);
    }

    case QVariant::List: {
        return (converBase64StringToVariant< QVariantList >(var));
    }

    case QVariant::Locale: {
        return (QLocale(var));
    }

    case QVariant::LongLong: {
        return (QString::number(var.toLongLong()));
    }

    case QVariant::Map: {
        return (converBase64StringToVariant< QVariantMap >(var));
    }

    case QVariant::Matrix: {
        QStringList list = var.split(';');
        if (list.size() != 6) {
            return (QVariant());
        }
        QMatrix d(list[ 0 ].toDouble(),
                  list[ 1 ].toDouble(),
                  list[ 2 ].toDouble(),
                  list[ 3 ].toDouble(),
                  list[ 4 ].toDouble(),
                  list[ 5 ].toDouble());
        return (d);
    }

    case QVariant::Transform: {
        QStringList list = var.split(';');
        if (list.size() != 9) {
            return (QVariant());
        }
        QTransform d(list[ 0 ].toDouble(),
                     list[ 1 ].toDouble(),
                     list[ 2 ].toDouble(),
                     list[ 3 ].toDouble(),
                     list[ 4 ].toDouble(),
                     list[ 5 ].toDouble(),
                     list[ 6 ].toDouble(),
                     list[ 7 ].toDouble(),
                     list[ 8 ].toDouble());
        return (d);
    }

    case QVariant::Matrix4x4: {
        QStringList list = var.split(';');
        if (list.size() != 16) {
            return (QVariant());
        }
        QMatrix4x4 d(list[ 0 ].toDouble(),
                     list[ 1 ].toDouble(),
                     list[ 2 ].toDouble(),
                     list[ 3 ].toDouble(),
                     list[ 4 ].toDouble(),
                     list[ 5 ].toDouble(),
                     list[ 6 ].toDouble(),
                     list[ 7 ].toDouble(),
                     list[ 8 ].toDouble(),
                     list[ 9 ].toDouble(),
                     list[ 10 ].toDouble(),
                     list[ 11 ].toDouble(),
                     list[ 12 ].toDouble(),
                     list[ 13 ].toDouble(),
                     list[ 14 ].toDouble(),
                     list[ 15 ].toDouble());
        return (d);
    }

    case QVariant::Palette: {
        return (converBase64StringToVariant< QPalette >(var));
    }

    case QVariant::Pen: {
        return (converBase64StringToVariant< QPen >(var));
    }

    case QVariant::Pixmap: {
        return (converBase64StringToVariant< QPixmap >(var));
    }

    case QVariant::Point: {
        QStringList list = var.split(';');
        if (list.size() != 2) {
            return (QVariant());
        }
        QPoint d(list[ 0 ].toInt(), list[ 1 ].toInt());
        return (d);
    }

    case QVariant::PointF: {
        QStringList list = var.split(';');
        if (list.size() != 2) {
            return (QPointF());
        }
        QPointF d(list[ 0 ].toDouble(), list[ 1 ].toDouble());
        return (d);
    }

    case QVariant::Polygon: {
        QPolygon d;
        QStringList list = var.split('|');
        if (0 == list.size()) {
            list = var.split(';');
            if (list.size() == 2) {
                d << QPoint(list[ 0 ].toDouble(), list[ 1 ].toDouble());
            }
            return (d);
        }
        for (int i = 0; i < list.size(); ++i) {
            QStringList plist = list[ i ].split(';');
            if (2 == plist.size()) {
                d.append(QPoint(plist[ 0 ].toDouble(), plist[ 1 ].toDouble()));
            }
        }
        return (d);
    }

    case QVariant::PolygonF: {
        QStringList list = var.split('|');
        QPolygonF d;
        if (0 == list.size()) {
            list = var.split(';');
            if (list.size() == 2) {
                d << QPointF(list[ 0 ].toDouble(), list[ 1 ].toDouble());
            }
            return (d);
        }
        for (int i = 0; i < list.size(); ++i) {
            QStringList plist = list[ i ].split(';');
            if (2 == plist.size()) {
                d.append(QPointF(plist[ 0 ].toDouble(), plist[ 1 ].toDouble()));
            }
        }
        return (d);
    }

    case QVariant::Quaternion: {
        return (converBase64StringToVariant< QQuaternion >(var));
    }

    case QVariant::Rect: {
        QStringList list = var.split(';');
        if (list.size() != 4) {
            return (QVariant());
        }
        QRect d(list[ 0 ].toInt(), list[ 1 ].toInt(), list[ 2 ].toInt(), list[ 3 ].toInt());
        return (d);
    }

    case QVariant::RectF: {
        QStringList list = var.split(';');
        if (list.size() != 4) {
            return (QVariant());
        }
        QRectF d(list[ 0 ].toDouble(), list[ 1 ].toDouble(), list[ 2 ].toDouble(), list[ 3 ].toDouble());
        return (d);
    }

    case QVariant::RegExp: {
        return (converBase64StringToVariant< QRegExp >(var));
    }

    case QVariant::RegularExpression: {
        return (converBase64StringToVariant< QRegularExpression >(var));
    }

    case QVariant::Region: {
        return (converBase64StringToVariant< QRegion >(var));
    }

    case QVariant::Size: {
        QStringList list = var.split(';');
        if (list.size() != 2) {
            return (QVariant());
        }
        QSize d(list[ 0 ].toInt(), list[ 1 ].toInt());
        return (d);
    }

    case QVariant::SizeF: {
        QStringList list = var.split(';');
        if (list.size() != 2) {
            return (QVariant());
        }
        QSizeF d(list[ 0 ].toDouble(), list[ 1 ].toDouble());
        return (d);
    }

    case QVariant::SizePolicy: {
        return (converBase64StringToVariant< QSizePolicy >(var));
    }

    case QVariant::String: {
        return (var);
    }

    case QVariant::StringList: {
        return (converBase64StringToVariant< QStringList >(var));
    }

    case QVariant::TextFormat: {
        return (converBase64StringToVariant< QTextFormat >(var));
    }

    case QVariant::TextLength: {
        return (converBase64StringToVariant< QTextLength >(var));
    }

    case QVariant::Time: {
        QTime t;
        t.fromString(var, Qt::ISODate);
        return (t);
    }

    case QVariant::UInt: {
        return (var.toUInt());
    }

    case QVariant::ULongLong: {
        return (var.toULongLong());
    }

    case QVariant::Url: {
        return (QUrl(var));
    }

    case QVariant::Vector2D: {
        return (converBase64StringToVariant< QVector2D >(var));
    }

    case QVariant::Vector3D: {
        return (converBase64StringToVariant< QVector3D >(var));
    }

    case QVariant::Vector4D: {
        return (converBase64StringToVariant< QVector4D >(var));
    }

    default:
        return (QVariant());
    }
    return (QVariant());
}

QString DA::doubleToString(const double a)
{
    char f        = 'g';
    int precision = 6;

    if (a > 1e6) {
        //当数据非常大时，精度需要根据大小进行调整
        int tmp = a / 1e6;
        while (tmp / 10 != 0)  // && precision < 16 precision不大于16
        {
            tmp /= 10;
            ++precision;
        }
        //精度还可以扩充，继续去处理小数位
        //取出double的小数位
        double decimal = a - floor(a);
        //把小数转换为最大可处理的整形以便处理
        tmp = decimal * pow(10, 9);
        //把整形的小位的0去除
        while (tmp)  // precision不大于16
        {
            if (0 != tmp % 10) {
                break;
            }
            tmp /= 10;
        }
        //把整形剩余位取出，作为精度
        while (tmp / 10 != 0)  // && precision < 16 precision不大于16
        {
            tmp /= 10;
            ++precision;
        }
    } else if ((a < 1e-6) && !qFuzzyCompare(a + 1, 1)) {
        //当数据非常小时
        //先把数据上调
        int i     = 0;
        double ta = a;
        while (ta < 1 && i < 308) {
            ta *= 10;
            ++i;  //防止ta == 0
        }
        precision = 16;
        int tmp   = ta * 1e16;
        //把整形的小位的0去除
        while (tmp && precision > 6)  // precision不小于6
        {
            if (0 == tmp % 10) {
                --precision;
            }
            tmp /= 10;
        }
    }
    return (QString::number(a, f, precision));
}
